package keter.combofs.api.adapters;

import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.keter.framework.core.util.ConcurrentUtil;
import keter.combofs.api.ComboFs;
import keter.combofs.id.IdMaker;
import keter.combofs.model.ComboFile;
import keter.combofs.model.FileMeta;
import keter.combofs.path.PathMaker;
import keter.combofs.persist.ComboFileDao;
import keter.combofs.util.IOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * 默认文件系统系统存储
 * Created by gulx@neusoft.com on 2019/11/11.
 */
public class ComboFsAdapter implements ComboFs {

    private static final Logger logger = LoggerFactory.getLogger(ComboFsAdapter.class);

    @Value("${combofs.root}")
    protected String root;

    @Autowired private IdMaker sequence;
    @Autowired private PathMaker pathMaker;
    @Autowired private ComboFileDao comboFileDao;

    private ListeningExecutorService service = ConcurrentUtil.service();

    @Override
    public ComboFile getComboFile(Long id) throws IOException {
        ComboFile comboFile = comboFileDao.find(id);
        String uri = pathMaker.getUri(id);
        comboFile.setUri(uri);
        comboFile.setFileBytes(Files.asByteSource(new File(uri)).read());
        return comboFile;
    }

    @Override
    public ComboFile getComboFile(String fileUri) throws IOException {
        throw new IOException("文件系统模式不支持直接使用Uri方式写入或访问文件！");
    }

    @Override
    public byte[] getBytes(Long id) throws IOException {
        return Files.asByteSource(new File(root+pathMaker.getPath(id)+id)).read();
    }

    @Override
    public byte[] getBytes(String fileUri) throws IOException {
        throw new IOException("文件系统模式不支持直接使用Uri方式写入或访问文件！");
    }

    @Override
    public ComboFile save(byte[] b) throws IOException {
        Long id = sequence.makeId();
        return save(id, b,null);
    }

    @Override
    public ComboFile save(InputStream in) throws IOException {
        return save(ByteStreams.toByteArray(in));
    }

    @Override
    public void save(byte[] b, String fileUri) throws IOException {
        throw new IOException("文件系统模式不支持直接使用Uri方式写入或访问文件！");
    }

    @Override
    public void save(InputStream in, String fileUri) throws IOException {
        throw new IOException("文件系统模式不支持直接使用Uri方式写入或访问文件！");
    }

    @Override
    public ComboFile save(byte[] b, FileMeta fileMeta) throws IOException {
        Long id = sequence.makeId();
        return save(id,b,fileMeta);
    }

    @Override
    public ComboFile save(byte[] b, String fileUri, FileMeta fileMeta) throws IOException {
        throw new IOException("文件系统模式不支持直接使用Uri方式写入或访问文件！");
    }

    private ComboFile save(Long id, byte[] b, FileMeta fileMeta) throws IOException {
        String uri = writeFile(b, id);
        ComboFile comboFile = ComboFile.build(id, uri, fileMeta, null);
        // 持久化
        comboFileDao.save(comboFile);
        // 异步持久化MD5
        service.submit(() -> {
            // 计算MD5
            String md5 = IOUtil.getMD5(b);
            // 更新MD5
            logger.info("更新文件md5: uri={},md5={}",uri,md5);
            comboFileDao.addMD5(id,md5);
        });
        return comboFile;
    }

    @Override
    public boolean delete(Long id){
        // 异步删除meta
        service.submit(() -> comboFileDao.delete(id));
        return new File(pathMaker.getUri(id)).delete();
    }

    @Override
    public boolean delete(String fileUri) {
        return false;
    }

    /**
     * 写入文件
     * @param b
     * @param id
     * @return
     * @throws IOException
     */
    private String writeFile(byte[] b, Long id) throws IOException {
        // 生成文件路径
        pathMaker.makePath(id.toString());
        // 文件写入
        String fileUri = pathMaker.getUri(id);
        Files.write(b, new File(fileUri));
        logger.info("文件:[{}]写入成功!",fileUri);
        return fileUri;
    }
}
